package com.xinke.module.system.manager.user;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.google.common.annotations.VisibleForTesting;
import com.mzt.logapi.context.LogRecordContext;
import com.mzt.logapi.service.impl.DiffParseFunction;
import com.mzt.logapi.starter.annotation.LogRecord;
import com.xinke.component.common.enums.CommonStatusEnum;
import com.xinke.component.common.util.collection.CollectionUtils;
import com.xinke.component.common.util.object.BeanUtils;
import com.xinke.component.common.util.sno.IdGen;
import com.xinke.component.datapermission.core.util.DataPermissionUtils;
import com.xinke.module.system.mapper.user.AdminUserMapper;
import com.xinke.module.system.mapper.user.UserPostMapper;
import com.xinke.module.system.model.entity.user.AdminUserDO;
import com.xinke.module.system.model.entity.user.UserPostDO;
import com.xinke.module.system.model.vo.user.AdminUserSaveReqVO;
import com.xinke.module.system.service.permission.PermissionService;
import com.xinke.module.system.service.tenant.TenantService;
import com.xinke.module.system.service.user.AdminUserService;
import com.xinke.module.system.service.user.DeptService;
import com.xinke.module.system.service.user.PostService;
import com.xinke.module.system.service.user.UserPostService;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.yaml.snakeyaml.events.Event.ID;

import javax.annotation.Resource;

import java.util.Collection;
import java.util.Set;

import static com.xinke.component.common.exception.util.ServiceExceptionUtil.exception;
import static com.xinke.component.common.util.collection.CollectionUtils.convertList;
import static com.xinke.component.common.util.collection.CollectionUtils.convertSet;
import static com.xinke.module.system.enums.ErrorCodeConstants.USER_COUNT_MAX;
import static com.xinke.module.system.enums.ErrorCodeConstants.USER_NOT_EXISTS;
import static com.xinke.module.system.enums.LogRecordConstants.*;

/**
 * @Author yzx
 * @CreateTime 2025/3/23 10:20
 * @Version 1.0
 * @Description:
 */
@Component
public class AdminUserManager {

    @Resource
    private TenantService tenantService;

    @Resource
    private AdminUserService userService;

    @Resource
    private DeptService deptService;

    @Resource
    private PostService postService;

    @Resource
    private UserPostService userPostService;
    @Resource
    private AdminUserMapper userMapper;
    @Resource
    private UserPostMapper userPostMapper;
    @Resource
    private PermissionService permissionService;
    @Transactional(rollbackFor = Exception.class)
    @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_CREATE_SUB_TYPE, bizNo = "{{#user.userId}}",
            success = SYSTEM_USER_CREATE_SUCCESS)
    public Long createAdminUser(AdminUserSaveReqVO createReqVO) {
        // 1.1 校验账户配合
        tenantService.handleTenantInfo(tenant -> {
            long count = userService.selectCount();
            if (count >= tenant.getAccountCount()) {
                throw exception(USER_COUNT_MAX, tenant.getAccountCount());
            }
        });
        // 1.2 校验正确性
        validateUserForCreateOrUpdate(null, createReqVO.getUserName(),
                createReqVO.getUserPhone(), createReqVO.getUserEmail(), createReqVO.getDeptId(), createReqVO.getPostIds());
        // 2.1 插入用户
        AdminUserDO user = userService.insertUser(createReqVO);

        // 2.2 插入关联岗位
        if (CollectionUtil.isNotEmpty(user.getPostIds())) {
            userPostService.insertBatch(convertList(user.getPostIds(),
                    postId -> new UserPostDO().setUserId(user.getUserId()).setPostId(postId).setUserPostId(IdGen.nextId())));
        }
        // 3. 记录操作日志上下文
        LogRecordContext.putVariable("user", user);
        return user.getUserId();
    }

    public AdminUserDO validateUserForCreateOrUpdate(Long userId, String userName, String userPhone, String userEmail, Long deptId, Set<Long> postIds){

            // 关闭数据权限，避免因为没有数据权限，查询不到数据，进而导致唯一校验不正确
            return DataPermissionUtils.executeIgnore(() -> {
                // 校验用户存在
                AdminUserDO user = userService.validateUserExists(userId);
                // 校验用户名唯一
                userService.validateUsernameUnique(userId, userName);
                // 校验手机号唯一
                userService.validateMobileUnique(userId, userPhone);
                // 校验邮箱唯一
                userService.validateEmailUnique(userId, userEmail);
                // 校验部门处于开启状态
                deptService.validateDeptList(CollectionUtils.singleton(deptId));
                // 校验岗位处于开启状态
                postService.validatePostList(postIds);
                return user;
            });
        }

    public void updateUser(AdminUserSaveReqVO updateReqVO) {
        updateReqVO.setUserPassword(null); // 特殊：此处不更新密码
        // 1. 校验正确性
        AdminUserDO oldUser = validateUserForCreateOrUpdate(updateReqVO.getUserId(), updateReqVO.getUserName(),
                updateReqVO.getUserPhone(), updateReqVO.getUserEmail(), updateReqVO.getDeptId(), updateReqVO.getPostIds());

        // 2.1 更新用户
        AdminUserDO updateObj = BeanUtils.toBean(updateReqVO, AdminUserDO.class);
        userMapper.updateById(updateObj);
        // 2.2 更新岗位
        updateUserPost(updateReqVO, updateObj);

        // 3. 记录操作日志上下文
        LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldUser, AdminUserSaveReqVO.class));
        LogRecordContext.putVariable("user", oldUser);
    }
    private void updateUserPost(AdminUserSaveReqVO reqVO, AdminUserDO updateObj) {
        Long userId = reqVO.getUserId();
        Set<Long> dbPostIds = convertSet(userPostMapper.selectListByUserId(userId), UserPostDO::getPostId);
        // 计算新增和删除的岗位编号
        Set<Long> postIds = CollUtil.emptyIfNull(updateObj.getPostIds());
        Collection<Long> createPostIds = CollUtil.subtract(postIds, dbPostIds);
        Collection<Long> deletePostIds = CollUtil.subtract(dbPostIds, postIds);
        // 执行新增和删除。对于已经授权的岗位，不用做任何处理
        if (!CollectionUtil.isEmpty(createPostIds)) {
            userPostMapper.insertBatch(convertList(createPostIds,
                    postId -> new UserPostDO().setUserId(userId).setPostId(postId)));
        }
        if (!CollectionUtil.isEmpty(deletePostIds)) {
            userPostMapper.deleteByUserIdAndPostId(userId, deletePostIds);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_DELETE_SUB_TYPE, bizNo = "{{#id}}",
            success = SYSTEM_USER_DELETE_SUCCESS)
    public void deleteUser(Long id) {
        // 1. 校验用户存在
        AdminUserDO user = validateUserExists(id);

        // 2.1 删除用户
        userMapper.deleteById(id);
        // 2.2 删除用户关联数据
        permissionService.processUserDeleted(id);
        // 2.2 删除用户岗位
        userPostMapper.deleteByUserId(id);

        // 3. 记录操作日志上下文
        LogRecordContext.putVariable("user", user);
    }
    @VisibleForTesting
    AdminUserDO validateUserExists(Long id) {
        if (id == null) {
            return null;
        }
        AdminUserDO user = userMapper.selectById(id);
        if (user == null) {
            throw exception(USER_NOT_EXISTS);
        }
        return user;
    }
}
